var ldap = require('ldapjs');
var clone = require('clone');

exports.client = {
	options: {
		url: '',
		username: '',
		password: '',
		filter: '',
		scope : 'sub',
		base : '',
		attributeToWalk: '', 
		attributes: []
	},
	visitedEntries : [],
	distinguishedNames : [],
	ldapClient : ldap.createClient({
		url : 'ldap://192.168.1.116:389'
	}),
	start : (function() {
		console.log(exports.client.options.attributeToWalk);
		exports.client.ldapClient.bind(exports.client.options.username,
				exports.client.options.password, function(err) {
				});
		var opts = {
			filter : exports.client.options.filter,
			scope : exports.client.options.scope,
			attributes :exports.client.options.attributes
		};

		exports.client.ldapClient.search(exports.client.options.base, opts, function(
				err, res) {
			var data = exports.client.foundEntries;
			res.on('searchEntry', function(entry) {
				entry.object.attributes = {
					objectclass : [ 'top', 'organizationalunit' ],
					ou : [ entry.object.cn ]
				};
				data.push(entry.object);
			});
			res.on('end', function(result) {
				exports.client.buildAttributeTree(data);
			});

		});

	}),
	walkTree : (function(entry, parent, entries, path) {
		if (typeof (entry) == 'undefined') {
			return;
		}
		console.log(exports.client.options.attributeToWalk);
		if (exports.client.visitedEntries[entry.dn] == null) {
			entry.refCount = 0;
			exports.client.visitedEntries[entry.dn] = true;

			if (entry[exports.client.options.attributeToWalk] != null) {
				if (typeof (entry[exports.client.options.attributeToWalk]) == 'string') {
					var child = entry[exports.client.options.attributeToWalk];
					if (typeof (exports.client.distinguishedNames[child]) != "undefined") {
						var newPath = clone(path);
						newPath.push(entry.dn);
						entry.children
								.push(exports.client.distinguishedNames[child]);
						exports.client.walkTree(
								exports.client.distinguishedNames[child],
								entry, entries, newPath);
					}
				} else {
					entry[exports.client.options.attributeToWalk]
							.forEach(function(child) {
								if (typeof (exports.client.distinguishedNames[child]) != "undefined") {
									var newPath = clone(path);
									newPath.push(entry.dn);
									entry.children
											.push(exports.client.distinguishedNames[child]);
									exports.client
											.walkTree(
													exports.client.distinguishedNames[child],
													entry, entries, newPath);
								}
							});
				}
			}
		} else {
			if (path.indexOf(entry.dn) > -1) {
				// mark them all cyclic
				entry.iscycle = 'true';
				for(i=path.indexOf(entry.dn);i<path.length;i++) {
					var pathElement = path[i];
					exports.client.distinguishedNames[pathElement].iscycle = 'true';
				}
				parent.children = [];
				parent.children.forEach(function(child) {
					if (child.dn != entry.dn) {
						newChildren.push(child);
					}
				});
			} else {
				entry.refCount++;
			}
		}
	}),
	cloneDn : (function(entryToChange, parent, entries) {
		if (entryToChange.refCount > 1) {
			copyForParent = entryToChange = clone(entryToChange);
			entries.push(entryToChange);
			copyForParent.isClone = true;
			
			var newChildren = [];
			parent.children.forEach(function(child) {
				if (child.dn == entryToChange.dn) {
					newChildren.push(entryToChange);
				} else {
					newChildren.push(child);
				}
			});
			parent.children = newChildren;

		}
		exports.client.visitedEntries[entryToChange.dn] = true;
		
		entryToChange.children.forEach(function(child) {
			exports.client.cloneDn(child, entryToChange, entries);
		});
	}),
	changeDn : (function(entryToChange, parent, entries) {
		entryToChange.originalDn = entryToChange.dn;
		entryToChange.dn = "OU=" + entryToChange.cn + "," + parent.dn;

		entryToChange.children.forEach(function(child) {
			exports.client.changeDn(child, entryToChange, entries);
		});
	}),
	buildAttributeTree : (function(entries) {
		var rootNodes = [];
		entries.forEach(function(entry) {
			exports.client.distinguishedNames[entry.dn] = entry;
			entry.children = [];
		});
		entries.forEach(function(entry) {
			exports.client.walkTree(entry, undefined, entries, []);
		});

		entries.forEach(function(entry) {
			if (typeof (entry.morph) != "undefined") {
				entry.morph(entries);
			}
		});
		entries.forEach(function(entry) {
			if (entry.refCount <= 0) {
				rootNodes.push(entry);
			} else {

			}
		});

		exports.client.visitedEntries = [];
		var root = {
			dn : exports.client.options.base,
			attributes : {
				objectclass : [ 'top', 'organization' ],
				o : [ exports.client.options.base ]
			},
			children : rootNodes
		};

		exports.client.visitedEntries = [];
		rootNodes.forEach(function(entry) {
			exports.client.cloneDn(entry, root, entries);
		});

		rootNodes.forEach(function(entry) {
			exports.client.changeDn(entry, root, entries);
		});
		exports.client.finishedCallback(entries, rootNodes);
	}),
	foundEntries : [],
	finishedCallback : (function(entries, rootNodes) {
	})
};
